package memberrank

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/resultx"
	enum "mall/service/backend/common/enum/setting"
	"mall/service/backend/common/utils/pointy"
	"mall/service/setting/model"
	"mall/service/setting/rpc/internal/svc"
	"mall/service/setting/rpc/types/setting"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetMemberRankListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetMemberRankListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMemberRankListLogic {
	return &GetMemberRankListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetMemberRankListLogic) GetMemberRankList(in *setting.BaseListReq) (*setting.MemberRankListResp, error) {
	if in.Filter == nil || len(*in.Filter) == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)
	// logrus.Info(fmt.Sprintf("GetMemberRankList preloadMap: %+v", preloadMap))
	// map[memberRank:[Id Name Code Desc PicId PicUrl] memberRankRestriction:[Id RankId TaskId Threshhold] memberRankRule:[Id RankId RuleType Regions Mode Value PeriodType Quota]]
	// logrus.Info(fmt.Sprintf("GetMemberRankList eagerLoadMap: %+v", eagerLoadMap))
	// map[memberRank:[memberRankRestriction memberRankRule]]

	resp := &setting.MemberRankListResp{}

	memberRankEntityName := model.RpcEntityNames.MemberRank
	_, hasSettingMap := model.RpcEntityPreloadMap[memberRankEntityName]
	if !hasSettingMap {
		return resp, nil
	}

	memberRankRepositoryName := model.RepositoryNames.MemberRank
	columnMap, hasColumnMap := model.RepositoryPreloadMap[memberRankRepositoryName]
	if !hasColumnMap {
		return resp, nil
	}

	var selectCols []string
	if preloadFields, hasPreloadFields := preloadMap[memberRankEntityName]; hasPreloadFields {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	// logrus.Info(fmt.Sprintf("GetMemberRankList filterMap: %+v", filterMap))
	// map[status:map[equalTo:[1]]]
	if filterMap == nil {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	// logrus.Info(fmt.Sprintf("GetMemberRankList orderBy: %s", orderBy))
	// sort ASC

	if len(orderBy) == 0 {
		orderBy = model.SysMemberRankColumns.Sort
	}

	res, count, err := l.svcCtx.MemberRank.GetList(l.ctx, model.M{
		"offset":  in.Offset,
		"limit":   in.Limit,
		"orderBy": orderBy,
		"select":  strings.Join(selectCols, ","),
	}, 2, filterMap)
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp.HasNextPage = &hasNextPage
	resp.HasPreviousPage = &hasPreviousPage

	if len(res) > 0 {
		var ids []any
		for _, v := range res {
			ids = append(ids, v.ID)
		}

		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, hasEagerLoadEntities := eagerLoadMap[memberRankEntityName]; hasEagerLoadEntities {
			for _, entity := range eagerLoadEntities {
				if entitySettingMap, hasEntitySettingMap := model.RpcEntityPreloadMap[entity]; hasEntitySettingMap {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idRestrictionMap := make(map[uint64][]*setting.MemberRankRestrictionInfo)
		restrictionEntityName := model.RpcEntityNames.MemberRankRestriction
		restrictionRepositoryName := model.RepositoryNames.MemberRankRestriction
		if _, hasEntitySettingMap := subEntitySettingMap[restrictionEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[restrictionEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[restrictionRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				var subSelectCols []string = modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				restrictionFilterMap := make(map[string]map[string][]any)
				restrictionFilterMap[model.SysMemberRankRestrictionColumns.RankID] = map[string][]any{
					"in": ids,
				}
				restrictionFilterMap[model.SysMemberRankRestrictionColumns.Status] = map[string][]any{
					"equalTo": []any{globalkey.StatusEnabled},
				}
				restrictions, _, err := l.svcCtx.MemberRank.GetRestrictionList(l.ctx, model.M{
					"orderBy": model.SysMemberRankRestrictionColumns.Sort,
					"select":  strings.Join(subSelectCols, ","),
				}, -1, restrictionFilterMap)
				if err != nil {
					return nil, err
				}

				if len(restrictions) > 0 {
					for _, v := range restrictions {
						idRestrictionMap[v.RankID] = append(idRestrictionMap[v.RankID], &setting.MemberRankRestrictionInfo{
							Id:        &v.RestrictionID,
							RankId:    &v.RankID,
							TaskId:    &v.TaskID,
							Threshold: pointy.GetPointer(uint32(v.Threshhold)),
							Sort:      pointy.GetPointer(uint32(v.Sort)),
							Status:    pointy.GetPointer(uint32(v.Status)),
						})
					}
				}
			}
		}

		idRuleMap := make(map[uint64][]*setting.MemberRankRuleInfo)
		ruleEntityName := model.RpcEntityNames.MemberRankRule
		ruleRepositoryName := model.RepositoryNames.MemberRankRule
		if _, hasEntitySettingMap := subEntitySettingMap[ruleEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[ruleEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[ruleRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				var subSelectCols []string = modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				ruleFilterMap := make(map[string]map[string][]any)
				ruleFilterMap[model.SysMemberRankRuleColumns.RankID] = map[string][]any{
					"in": ids,
				}
				ruleFilterMap[model.SysMemberRankRuleColumns.Status] = map[string][]any{
					"equalTo": []any{globalkey.StatusEnabled},
				}
				rules, _, err := l.svcCtx.MemberRank.GetRuleList(l.ctx, model.M{
					"orderBy": model.SysMemberRankRuleColumns.Sort,
					"select":  strings.Join(subSelectCols, ","),
				}, -1, ruleFilterMap)
				if err != nil {
					return nil, err
				}

				if len(rules) > 0 {
					for _, v := range rules {
						var value *string
						var regions *string
						var periodType *uint32
						var quota *uint32
						switch v.RuleType {
						case enum.MemberRankRuleTypeDiscount, enum.MemberRankRuleTypeGems:
							switch v.Mode {
							case enum.MemberRankRuleModeAmount:
								value = pointy.GetPointer(moneyx.FormatGem(int64(v.Value)))
							case enum.MemberRankRuleModeDiscount:
								value = pointy.GetPointer(strconv.FormatInt(int64(v.Value), 10))
							case enum.MemberRankRuleModeFixed:
								value = pointy.GetPointer(moneyx.FormatGem(int64(v.Value)))
							}
						case enum.MemberRankRuleTypeFreeShipping:
							if v.Regions.Valid {
								regions = pointy.GetPointer(string(v.Regions.JSON))
							}
						case enum.MemberRankRuleTypeExtraPoint:
							value = pointy.GetPointer(strconv.FormatInt(int64(v.Value), 10))
						case enum.MemberRankRuleTypeCoupon:
							value = pointy.GetPointer(strconv.FormatInt(int64(v.Value), 10))
							periodType = pointy.GetPointer(uint32(v.PeriodType))
							quota = pointy.GetPointer(uint32(v.Quota))
						}

						idRuleMap[v.RankID] = append(idRuleMap[v.RankID], &setting.MemberRankRuleInfo{
							Id:         &v.RuleID,
							RankId:     &v.RankID,
							RuleType:   pointy.GetPointer(uint32(v.RuleType)),
							Regions:    regions,
							Mode:       pointy.GetPointer(uint32(v.Mode)),
							Value:      value,
							PeriodType: periodType,
							Quota:      quota,
							Sort:       pointy.GetPointer(uint32(v.Sort)),
							Status:     pointy.GetPointer(uint32(v.Status)),
						})
					}
				}
			}
		}

		for _, v := range res {
			var restrictions []*setting.MemberRankRestrictionInfo
			if rs, ok := idRestrictionMap[v.ID]; ok {
				restrictions = rs
			}
			var rules []*setting.MemberRankRuleInfo
			if rs, ok := idRuleMap[v.ID]; ok {
				rules = rs
			}

			resp.List = append(resp.List, &setting.MemberRankInfo{
				Id:             &v.ID,
				Name:           &v.Name,
				Code:           &v.Code,
				Description:    &v.Description,
				Remark:         &v.Remark,
				PicId:          &v.PicID,
				PicUrl:         &v.PicURL,
				PointThreshold: pointy.GetPointer(uint32(v.PointThreshold)),
				IsDefault:      pointy.GetPointer(uint32(v.IsDefault)),
				Sort:           pointy.GetPointer(uint32(v.Sort)),
				Status:         pointy.GetPointer(uint32(v.Status)),
				CreatedAt:      pointy.GetPointer(modelx.FormatTime(v.CreatedAt, "")),
				UpdatedAt:      pointy.GetPointer(modelx.FormatTime(v.UpdatedAt, "")),
				DeletedAt:      pointy.GetPointer(modelx.FormatNullDotTime(v.DeletedAt, "")),
				Restrictions:   restrictions,
				Rules:          rules,
			})
		}
	}

	return resp, nil
}
